JS-[promises篇]-消耗一個promise以及串接promise 與錯誤處理


這裡要繼續討論的是如何使用或處理 Promise 得到的最終狀態,通常是通過 .then() 方法来獲取 Promise 的值或處理 Promise 的狀態

複習promise

當我們寫下:

會得到什麼?其實這一段就等同於我們在建構promise,也就是說,這段Fetch get請求,建構了promise,不過仍然是一個懸而未決的狀態<pending>

假定中樂透的狀態.then(fn(){... return})

而我要對自己建構的promise/樂透有信心啊!所以起手式都是假定promise的<pending>狀態將會進入“fulfilled/已實現”的狀態,所以我們會用.then()這個語法來處理“fulfilled/已實現”的狀態,也可以想成.then()就是在計畫我中樂透的並收到中獎(資料)的規劃

response在控制台的回傳是這樣:

response.json()

我們透過Fetch API取的的資料會是一個reaponse打包的物件,因此我們可以利用.json()方式將物件轉成可以運用的字串,把response.json()結果輸出來看看

promise return promise 要一層一層剝開..

是的沒有看錯,當我們使用.then()方法時,由裡面的callback fn接收response參數,即使用.json()的方式將response解析,response.json()仍然會回傳一個懸而未決的promise喔!

所以該怎麼做?一樣就是將response.json(),假定為這個promise是一個將來成功得到資料的狀態,所以我們將這個狀態回傳出去,再用一個假定為成功中獎或是得到資料的狀態來接這個promise,也就是另外一個.then()

為什麼在這裡response.json()是一個promise?

由於這點對我來說很重要,因為我會不自覺得繼續寫下去,而不是想到要用另外一個.then()來接

其實是這樣的,fetch()是一個API,它接收到的response是一個 Stream 物件,response.json()是一個非同步操作,取出response所有内容,並將其轉為json格式,這裡有一個重點關鍵字:response.json()是一個非同步操作

  • 我是這樣自我解釋:
    • 我透過fetch API建構promise(仍然是懸而未決的狀態),然後後台繼續執行向遠端非同步請求
    • 而我假定這個會成功,所以用.then()來做成功接收狀態的處理,就接收了從遠端回傳了response物件
    • 然後我在這個.then()中再為這個response使用.json()的做格式轉換的處理,所以在這裡也是非同步行為
    • 因為做格式轉換的動作,他把你這個.json()的請求,丟到後台執行,不知道有沒有解析成功(promise懸而未決的狀態)
    • 所以我也就假定這個.json()會成功,就先return response.json(),用下一個.then()來接收成功的結果(response.json()被解析完的)data,於是就得到了資料

成功回傳


現在來繼續串接promise

把鄰近國家的資料也一併ajax call出來,其實我在callbak hell寫過一次,這裡是用promise的寫法將巢狀的callback hell變成平行時空!

先把上面的promise簡化的優雅一點

加入鄰國的第二個ajax call


這裡邏輯都跟callback hell寫法類似,只是promise的寫法讓我們比較好閱讀跟維護,promise很好的將callback hell 那種程式深深深幾許的巢狀寫法展開來寫,運用.then()方法將ajax calla有序列的實現非同步請求(順序性)這是一大優化!

接下來是繼續介紹promise的錯誤處理,後續還會深入promise語法糖async 與await的寫法


promise的錯誤處理.catch()

使用fetch API最常見的promise進入到rejected的狀態,大部分是使用者電腦離線的狀況居多,連不到API

想要的狀態是,即使在離線狀態,做網路請求時,仍會出現一些錯誤提示,在還沒做任何錯誤處理下,程式碼如下:


上面紅字提示是說,fetch 回傳的promise錯誤狀態,我沒有接住並作出處理
現在要練習的是如何為promise做出rejected的錯誤提示

在.then()的最後面加入 .catch()

.catch((err) => console.log(err))
當任何一個.then方法中出現promise rejected的狀態,都會被移到這個.catch的方法中,裡面會帶一個err參數(錯誤訊息的物件),我試著將它打印出來

自己寫一個錯誤處理的函式


加入在.catch()裡


promise的最後.finally()

.finally()方法是,不論promise的狀態是fulfilled 還是 rejected,在.finally()的程式碼都會在其後被執行,要記得.finally()之所以可以寫在.catch()的後面,原因是,.catch()最後也會返回一個promise

  • 實用性:通常很少使用到,最有可能會用的情況是隱藏“loading spinner",就是不論promise是跑.then()還是.catch()在執行結果顯示畫面之前,可以利用.finally()把loading spinner的狀態隱藏起來,以下用黯淡下去的容器為練習

程式碼修改,把按下按鈕會把國家卡片顯示出來的程式碼挪移到.finally()這行,因為不管是.then()還是.catch()都會有這個動作,就這個動作統一挪至.finally()使用


加入.finally()

正常顯示的情況,會執行最後的.finally()程式碼

錯誤顯示的情況,也會執行最後的.finally()程式碼


補充:手動丟出錯誤 throw Err

promise章節很重要,所以我在這裡的練習費勁了一些心力,好讓自己能理解為什麼,最後來到promise的手動丟出錯誤的補充章節,在上述的練習裡,嘗試來做一個動作會發現一個驚人的事實:

這也是為什麼會有throw new Error()的語法存在
在找不到api的url時,我們試試輸出response物件來看一下

當畫面能正確顯示ok的值會出現這樣

我們可以透過手動創建錯誤的建構子並寫下錯誤的相關訊息與狀態,再用throw關鍵字拋出給.catch()處理

像上面這樣,promise才會立即拋出錯誤處理也就是rejected的狀態

#Promise #return response.json() #.then() #.catch() #throw new Error()







你可能感興趣的文章

【THM Walkthrough】Breaching Active Directory

【THM Walkthrough】Breaching Active Directory

CSS 魔術師 Houdini API 介紹

CSS 魔術師 Houdini API 介紹

前端必備 JavaScript, jQuery 表示QQ

前端必備 JavaScript, jQuery 表示QQ






留言討論